/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: ImageSlicing.cxx,v $

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//
// This example shows how to load a 3D image into VTK and then reformat
// that image into a different orientation for viewing.  It uses
// vtkImageReslice for reformatting the image, and uses vtkImageActor
// and vtkInteractorStyleImage to display the image.  This InteractorStyle
// forces the camera to stay perpendicular to the XY plane.
//
// Thanks to David Gobbi of Atamai Inc. for contributing this example.
//

#include "vtk_include.h"
#include "golImageAlgorithm.h"
#include <iostream>
#include <fstream>
#include <string.h>
#include <limits> //for clearing cin stream on bad input data

using namespace std;

// for reading and display
vtkJPEGReader *reader;
vtkImageActor *actor;

// filter params
string filename;
int born_neighbors;
int live_neighbors;

// for filtering the image
const int MAX_PASSES=100;
int numPasses = 0;
golImageAlgorithm *filters[MAX_PASSES];

int getIntInRange(const char *prompt, int min, int max)
{
	int input;

	while(true)
	{
		cout << prompt;
		cin >> input;

		// bad input
		if(!cin.good())
		{
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(),'\n');
			cout << "The value must be an integer.\n";
		}
		else if(input < min)
			cout << "The value must be greater than or equal to " << min << ".\n";
		else if(input > max)
			cout << "The value must be less than or equal to " << max << ".\n";
		else
			return input;
	}
}

void getParams(){
	bool gotFile = false;
	while(!gotFile){
		cout << "Input file (must be .jpg): ";
		cin >> filename;
		
		if(filename.length()>4){
			string ext = filename.substr(filename.length()-4);
			if(stricmp(ext.c_str(),".JPG")==0){
				ifstream fin(filename.c_str());
				if(!fin.fail())
				{
					fin.close();
					reader = vtkJPEGReader::New();
					reader->SetFileName(filename.c_str());
					reader->Update();
					gotFile=true;
				} else {
					cout << "File doesn't exist\n";
				}
			} else {
				cout << "File extension must be '.jpg'\n";
			}
		}
	}
	born_neighbors = getIntInRange("Minimum neighbors for birth (1-26): ",1,26);
	live_neighbors = getIntInRange("Minimum neighbors to live (1-26): ",1,26);
}

class vtkSimpleTimerCallback : public vtkCommand
{
	public:
		static vtkSimpleTimerCallback *New()
		{
			vtkSimpleTimerCallback *cb = new vtkSimpleTimerCallback;
			return cb;
		}

		void setTimerToWatch(int timerId)
		{
			timerToWatch = timerId;
		}

		void setInteractor(vtkRenderWindowInteractor *i)
		{
			interactor = i;
		}

		virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
		{
			if(vtkCommand::TimerEvent == eventId)
			{
				int timerId = *static_cast<int*>(callData);
				if(timerId != timerToWatch) return;
				
				
				int renderAgain=getIntInRange("(0=Redraw,1=Filter,2=Reset):",0,2);
				if(renderAgain==1){
					if(numPasses<MAX_PASSES){
						filters[numPasses] = golImageAlgorithm::New();
						filters[numPasses]->SetbornLow(born_neighbors);
						filters[numPasses]->SetliveLow(live_neighbors);
						if(numPasses==0)
						{
							filters[0]->SetInputConnection(reader->GetOutputPort());
						}
						else
						{
							filters[numPasses]->SetInputConnection(filters[numPasses-1]->GetOutputPort());
						}
						actor->SetInput(filters[numPasses]->GetOutput());
						numPasses++;
					} else {
						cout << "Maximum filter passes reached.\n";
					}
				} else if(renderAgain==2){
					actor->SetInput(NULL);
					while(numPasses>0) filters[--numPasses]->Delete();
					getParams();
					actor->SetInput(reader->GetOutput());
				}
				
				interactor->Render();
			}
		}
	private:
		int timerToWatch;
		vtkRenderWindowInteractor *interactor;
};

// The program entry point
int main (int argc, char **argv)
{
  // Start by loading some data
  getParams();

  // Display the image
  actor = vtkImageActor::New();
  actor->SetInput(reader->GetOutput());

  vtkRenderer *renderer = vtkRenderer::New();
  renderer->AddActor(actor);

  vtkRenderWindow *window = vtkRenderWindow::New();
  window->AddRenderer(renderer);
  window->SetSize(500,500);

  // Set up the interaction
  vtkInteractorStyleImage *imageStyle = vtkInteractorStyleImage::New();
  vtkRenderWindowInteractor *interactor = vtkRenderWindowInteractor::New();
  //interactor->SetInteractorStyle(imageStyle);
  window->SetInteractor(interactor);
  window->Render();

  // set up callback to reprocess image
  vtkSimpleTimerCallback *cb = vtkSimpleTimerCallback::New();
  interactor->AddObserver(vtkCommand::TimerEvent, cb);
  cb->setTimerToWatch(interactor->CreateRepeatingTimer(100));
  cb->setInteractor(interactor);

  // Start interaction
  // The Start() method doesn't return until the window is closed by the user
  interactor->Start();

  // Clean up
  interactor->Delete();
  imageStyle->Delete();
  window->Delete();
  renderer->Delete();
  actor->Delete();
  reader->Delete();
}